<?php
namespace Lib\Http;

/**
 * HTTP 响应控制器。
 *
 * @author SUSISOY
 *
 */
final class Response {
	private $_header = array();
	private $_body = '';
	private $_status = NULL;

	public function __construct($message = '', $cookie = NULL) {
		while ($message) {
			$line = strstr($message, "\r\n", TRUE);
			
			$message = substr($message, strlen($line) + 2);
			
			if ($line == '') {
				break;
			}
			
			if (!$this->_status) {
				preg_match('#^HTTP/\S+\s+(\d+)\s?#i', $line, $status) && $this->_status = intval($status[1]);
			} elseif (preg_match('/^([\w\-]+):\s*(.+)\s*$/i', $line, $info)) {
				$x = str_replace(' ', '-', ucwords(str_replace('-', ' ', strtolower($info[1]))));
				
				switch ($x) {
					case 'Set-Cookie' :
						isset($this->_header[$x]) || $this->_header[$x] = [];
						
						$this->_header[$x][] = $info[2];
						
						break;
					default :
						$this->_header[$x] = $info[2];
				}
			}
		}
		
		$this->_body = $message ?  : '';
		
		if (isset($this->_header['Content-Encoding']) && strtolower($this->_header['Content-Encoding']) == 'gzip') {
			// 数据前三个字节符合 gzip 数据格式规范时，对 gzip 数据进行解压。
			if (strlen($this->_body) >= 18 && ord($this->_body[0]) == 0x1F && ord($this->_body[1]) == 0x8B && ord($this->_body[2]) == 0x08) {
				$offset = 10;
				
				$flag = ord($this->_body[3]);
				
				if ($flag & 4) {
					$ext = unpack('v', substr($this->_body, 10, 2));
					$offset += 2 + $ext[1];
				}
				
				$flag & 8 && $offset = strpos($this->_body, chr(0), $offset) + 1;
				
				$flag & 16 && $offset = strpos($this->_body, chr(0), $offset) + 1;
				
				$flag & 2 && $offset += 2;
				
				$this->_body = gzinflate(substr($this->_body, $offset));
				$this->_body === FALSE && $this->_body = '';
			}
		}
	}

	public function __get($name) {
		switch ($name) {
			case 'header' :
				return $this->_header;
			case 'body' :
				return $this->_body;
			case 'status' :
				return $this->_status;
			case 'meta' :
				return $this->meta();
			case 'type' :
				return $this->type();
			case 'charset' :
				return $this->charset();
			case 'title' :
				return $this->title();
		}
		
		return NULL;
	}

	/**
	 * 获得 HTTP 响应消息指定头信息。
	 *
	 * @param string $name
	 * @return array|string|null
	 */
	public function header($name = NULL) {
		if (!$name) {
			return $this->_header;
		}
		
		$name = str_replace(' ', '-', ucwords(str_replace('-', ' ', strtolower($name))));
		
		return isset($this->_header[$name]) ? $this->_header[$name] : NULL;
	}

	/**
	 * 获得 HTTP 响应消息体数据内容。
	 *
	 * @return string
	 */
	public function body() {
		return $this->_body;
	}

	/**
	 * 获得 HTTP 响应消息体数据内容。
	 *
	 * @return string
	 */
	public function __toString() {
		return $this->body();
	}

	/**
	 * 获得 HTML 内容中的 META 列表。
	 *
	 * @param string $name
	 * @return array
	 */
	public function meta($name = NULL) {
		static $meta = NULL;
		
		if ($name) {
			$name = str_replace(' ', '-', ucwords(str_replace('-', ' ', strtolower($name))));
			
			if (isset($meta[$name])) {
				return $meta[$name];
			}
		}
		
		if (!is_null($meta)) {
			return $meta;
		}
		
		$meta = array();
		
		if ($this->type() == 'text/html') {
			preg_match_all('/<meta\s+(http\-equiv|name|content)\s*=\s*("|\')([^\\2]+)\\2\s*(?:http\-equiv|name|content)\s*=\s*("|\')([^\\4]+)\\4/Ui', $this->_body, $list);
			
			foreach ($list[3] as $k => $name) {
				$name = str_replace(' ', '-', ucwords(str_replace('-', ' ', strtolower($list[1][$k] == 'content' ? $list[5][$k] : $name))));
				
				$value = $list[1][$k] == 'content' ? $list[3][$k] : $list[5][$k];
				
				switch ($name) {
					case 'Set-Cookie' :
						isset($meta['Set-Cookie']) || $meta['Set-Cookie'] = [];
						
						$meta['Set-Cookie'][] = $value;
						
						break;
					case 'Content-Type' :
					case 'Content-Language' :
					case 'Expires' :
					case 'Pragma' :
					case 'Refresh' :
					case 'Keywords' :
					case 'Deion' :
					case 'Description' :
					case 'Robots' :
					case 'Author' :
					case 'Copyright' :
					default :
						$meta[$name] = $value;
				}
			}
		}
		
		return $meta;
	}

	/**
	 * 获得在 HTTP 消息头中指定的字符集，字符集名称将被转为小写。
	 *
	 * @return string|null
	 */
	public function charset() {
		static $charset = '';
		
		if ($charset !== '') {
			return $charset;
		}
		
		if (isset($this->_header['Content-Type']) && preg_match('/charset\s*=\s*(.+)/i', $this->_header['Content-Type'], $charset)) {
			$charset = strtolower(trim($charset[1]));
		} elseif ($this->type() == 'text/html') {
			$meta = $this->meta();
			
			if (isset($meta['Content-Type']) && preg_match('/charset\s*=\s*(.+)/i', $meta['Content-Type'], $charset)) {
				$charset = strtolower(trim($charset[1]));
			}
		}
		
		$charset || $charset = NULL;
		
		return $charset;
	}

	/**
	 * 获得 HTML 内容中的 Title 内容。
	 *
	 * @return string|null
	 */
	public function title() {
		static $title = '';
		
		if ($title !== '') {
			return $title;
		}
		
		if ($this->type() == 'text/html') {
			$title = preg_match('#<head>.*<title>(.+)</title>.*</head>#Uis', $this->_body, $title) ? $title[1] : '';
		}
		
		$title || $title = NULL;
		
		return $title;
	}

	/**
	 * 获得在 HTTP 消息头中指定的类型，类型名称将被转为小写。
	 *
	 * @return string|null
	 */
	public function type() {
		static $type = '';
		
		if ($type !== '') {
			return $type;
		}
		
		if (isset($this->_header['Content-Type'])) {
			$type = strtolower(strtok($this->_header['Content-Type'], ';'));
		}
		
		$type || $type = NULL;
		
		return $type;
	}

	/**
	 * 获取 HTTP 响应状态码
	 *
	 * @return int
	 */
	public function status() {
		return $this->_status;
	}
}